use vertica_rs::error::error_response::{ErrorResponse, ErrorSeverity};

#[test]
fn test_error_response_parsing() {
    // Test case 1: Basic error response
    let mut data = vec![];
    data.push(b'S'); // Severity
    data.extend_from_slice(b"ERROR\0");
    data.push(b'C'); // SQL State
    data.extend_from_slice(b"42P01\0");
    data.push(b'M'); // Message
    data.extend_from_slice(b"relation \"users\" does not exist\0");
    data.push(0); // End marker

    let error = ErrorResponse::parse_from_message(&data).unwrap();
    
    assert_eq!(error.severity, Some(ErrorSeverity::Error));
    assert_eq!(error.sql_state(), Some("42P01"));
    assert_eq!(error.message(), Some("relation \"users\" does not exist"));
}

#[test]
fn test_error_response_with_detail() {
    let mut data = vec![];
    data.push(b'S');
    data.extend_from_slice(b"FATAL\0");
    data.push(b'C');
    data.extend_from_slice(b"28P01\0");
    data.push(b'M');
    data.extend_from_slice(b"password authentication failed for user \"testuser\"\0");
    data.push(b'D');
    data.extend_from_slice(b"Role \"testuser\" does not exist.\0");
    data.push(b'H');
    data.extend_from_slice(b"Check the username and password\0");
    data.push(0);

    let error = ErrorResponse::parse_from_message(&data).unwrap();
    
    assert_eq!(error.severity, Some(ErrorSeverity::Fatal));
    assert_eq!(error.sql_state(), Some("28P01"));
    assert_eq!(error.message(), Some("password authentication failed for user \"testuser\""));
    assert_eq!(error.detail, Some("Role \"testuser\" does not exist.".to_string()));
    assert_eq!(error.hint, Some("Check the username and password".to_string()));
}

#[test]
fn test_empty_error_response() {
    let error = ErrorResponse::parse_from_message(&[0]).unwrap();
    assert!(error.message.is_none());
    assert!(error.sql_state.is_none());
    assert!(error.severity.is_none());
}

#[test]
fn test_error_response_to_error() {
    let mut data = vec![];
    data.push(b'S');
    data.extend_from_slice(b"ERROR\0");
    data.push(b'M');
    data.extend_from_slice(b"test error message\0");
    data.push(0);

    let error_response = ErrorResponse::parse_from_message(&data).unwrap();
    let vertica_error = error_response.to_error();
    
    assert!(matches!(vertica_error, vertica_rs::error::VerticaError::Query(_)));
    assert_eq!(vertica_error.to_string(), "Query error: test error message");
}

#[test]
fn test_fatal_error_to_connection_error() {
    let mut data = vec![];
    data.push(b'S');
    data.extend_from_slice(b"FATAL\0");
    data.push(b'M');
    data.extend_from_slice(b"connection error\0");
    data.push(0);

    let error_response = ErrorResponse::parse_from_message(&data).unwrap();
    let vertica_error = error_response.to_error();
    
    assert!(matches!(vertica_error, vertica_rs::error::VerticaError::Connection(_)));
    assert_eq!(vertica_error.to_string(), "Connection error: connection error");
}

#[test]
fn test_sql_state_checking() {
    let mut data = vec![];
    data.push(b'C');
    data.extend_from_slice(b"23505\0"); // Unique violation
    data.push(b'M');
    data.extend_from_slice(b"duplicate key value violates unique constraint\0");
    data.push(0);

    let error = ErrorResponse::parse_from_message(&data).unwrap();
    assert!(error.is_sql_state("23505"));
    assert!(!error.is_sql_state("42P01"));
}

#[test]
fn test_complex_error_response() {
    let mut data = vec![];
    data.push(b'S');
    data.extend_from_slice(b"ERROR\0");
    data.push(b'C');
    data.extend_from_slice(b"42703\0");
    data.push(b'M');
    data.extend_from_slice(b"column \"email\" does not exist\0");
    data.push(b'D');
    data.extend_from_slice(b"Perhaps you meant to reference the column \"users.email\".\0");
    data.push(b'P');
    data.extend_from_slice(b"42\0");
    data.push(b'W');
    data.extend_from_slice(b"SELECT name, email FROM users WHERE id = 1\0");
    data.push(0);

    let error = ErrorResponse::parse_from_message(&data).unwrap();
    
    assert_eq!(error.severity, Some(ErrorSeverity::Error));
    assert_eq!(error.sql_state(), Some("42703"));
    assert_eq!(error.message(), Some("column \"email\" does not exist"));
    assert_eq!(error.detail, Some("Perhaps you meant to reference the column \"users.email\".".to_string()));
    assert_eq!(error.position, Some("42".to_string()));
    assert_eq!(error.where_clause, Some("SELECT name, email FROM users WHERE id = 1".to_string()));
}

#[test]
fn test_async_message_string_methods() {
    use vertica_rs::conn::async_conn::AsyncMessage;
    use bytes::BytesMut;
    
    // Test read_string with valid null-terminated string
    let mut msg = AsyncMessage {
        message_type: b'E',
        data: BytesMut::from(&b"test string\0"[..]),
    };
    assert_eq!(msg.read_string().unwrap(), "test string");
    
    // Test read_string with empty string
    let mut msg = AsyncMessage {
        message_type: b'E',
        data: BytesMut::from(&b"\0"[..]),
    };
    assert_eq!(msg.read_string().unwrap(), "");
    
    // Test read_tagged_string
    let mut msg = AsyncMessage {
        message_type: b'E',
        data: BytesMut::from(&b"Mtest message\0"[..]),
    };
    let (field_type, value) = msg.read_tagged_string().unwrap();
    assert_eq!(field_type, b'M');
    assert_eq!(value, "test message");
    
    // Test read_tagged_string with end marker
    let mut msg = AsyncMessage {
        message_type: b'E',
        data: BytesMut::from(&b"\0"[..]),
    };
    let (field_type, value) = msg.read_tagged_string().unwrap();
    assert_eq!(field_type, 0);
    assert_eq!(value, "");
}